package com.example.springbootwebsocket.websocket;


import com.example.springbootwebsocket.DTO.NoticeWebsocketResp;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * ServerEndpoint是一个类层次的注解，其作用就是将该类注册为一个websocket服务器端点
 * 其value值将被用于监听用户连接的终端访问的URL地址值，客户端可以通过这个URL来连接到WebSocket服务器端
 */
@ServerEndpoint("/notice/{userId}")
@Component
@Slf4j
public class NoticeWebsocket {
    private static ObjectMapper objectMapper = new ObjectMapper();

    //记录连接的客户端
    private static Map<String, Session> clients = new ConcurrentHashMap<>();

    //记录用户对应的连接
    private static Map<String, Set<String>> conns = new ConcurrentHashMap<>();

    //sessionId
    //TODO 此处需要将这些成员变量给替换掉，在多线程环境下会出现问题（建议用Jmeter压测一下，暴露出问题）
    //TODO  将用户信息userId存入session中
    private String sessionId;

    //用户id
    private String userId;


    /**
     * 连接建立成功调用的方法
     * @param session
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        this.sessionId = session.getId();
        this.userId = userId;
        clients.put(sessionId, session);

        Set<String> clientSet = conns.get(userId);
        //userId第一次连接
        if (clientSet == null) {
            clientSet = new HashSet<String>();
            clientSet.add(sessionId);
            conns.put(userId, clientSet);
        }else {//userId已经连接
            clientSet.add(sessionId);
        }
        log.info("用户{}连接成功，sessionId为{}", userId, sessionId);
    }

    /**
     * 断开连接时调用的方法
     */
    @OnClose
    public void onClose() {
        clients.remove(this.sessionId);
        Set<String> clientSet = conns.get(userId);
        if (clientSet != null) {
            clientSet.remove(sessionId);
        }
        log.info("用户{}断开连接，sessionId为{}", userId, sessionId);
    }

    /**
     * 判断是否连接的method
     */
    public static boolean isConnected(String userId) {
        Set<String> clientSet = conns.get(userId);
        return clientSet != null && clientSet.size() > 0;
    }


    /**
     * 发送给所有用户
     *
     */
    public static void sendMessage(NoticeWebsocketResp noticeWebsocketResp) throws JsonProcessingException {
        String message = objectMapper.writeValueAsString(noticeWebsocketResp);
        for (Session session1 : NoticeWebsocket.clients.values()) {
            try {
                session1.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     *  发送给所有用户
     */
    public static void sendAll(String noticeType) {
        NoticeWebsocketResp  noticeWebsocketResp = new NoticeWebsocketResp();
        noticeWebsocketResp.setNoticeType(noticeType);
        try {
            sendMessage(noticeWebsocketResp);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据用户id发送给指定用户
     *
     */
    public static void sendMessageByUserId(String userId, NoticeWebsocketResp noticeWebsocketResp){
        if(!StringUtils.isEmpty(userId)){
            String message = null;
            try {
                message = objectMapper.writeValueAsString(noticeWebsocketResp);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            Set<String> clientSet = conns.get(userId);
            if (clientSet != null) {
                for (String sessionId : clientSet) {
                    Session session = clients.get(sessionId);
                    try {
                        session.getBasicRemote().sendText(message);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 收到客户端消息后调用的方法
     */
    @OnMessage
    public void onMessage(String message) {
        log.info("用户{}收到消息：{}", userId, message);
    }

    /**
     * 发生错误是的回调函数
     */
    @OnError
    public void onError(Session session, Throwable throwable) {
        log.error("用户{}发生错误：{}", userId, throwable.getMessage());
        throwable.printStackTrace();
    }



}
